// <copyright file="DirectionalData.cs" company="TenneySoftware">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author>Robert Tenney</author>
// <email>rob10e@yahoo.com</email>
// <date>April 2009</date>
// <summary>A class to determine the data related to the points surrounding a certain point based on the direction given.</summary>

// License:

// Product: RPGRoguelikeEngine .Net
// Author: Robert N. Tenney
// Copyright: April 2009

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation version 2
// of the License.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// This license covers all source code, binaries, and other materials related to this project
// unless specifically stated otherwise.

using System;
using System.Drawing;

namespace TenneySoftware.Engine {
    /// <summary>
    /// A class to determine the data related to the points surrounding a certain point based
    /// on the direction given.
    /// </summary>
    public class DirectionalData {
        /// <summary>
        /// Point forward of center.
        /// </summary>
        private Point forward;

        /// <summary>
        /// Point behind the center.
        /// </summary>
        private Point behind;

        /// <summary>
        /// Point to the left of center.
        /// </summary>
        private Point left;

        /// <summary>
        /// Point to the right of center.
        /// </summary>
        private Point right;

        /// <summary>
        /// Point forward and to the right of center.
        /// </summary>
        private Point forwardRight;

        /// <summary>
        /// Point forward and to the left of center.
        /// </summary>
        private Point forwardLeft;

        /// <summary>
        /// Point behind and to the right of center.
        /// </summary>
        private Point behindRight;

        /// <summary>
        /// Point behind and to the left of center.
        /// </summary>
        private Point behindLeft;

        /// <summary>
        /// The center point.
        /// </summary>
        private Point center;

        /// <summary>
        /// Direction forward of center.
        /// </summary>
        private Direction forwardDirection;

        /// <summary>
        /// Direction to the left of center.
        /// </summary>
        private Direction leftDirection;

        /// <summary>
        /// Direction to the right of center.
        /// </summary>
        private Direction rightDirection;

        /// <summary>
        /// Direction behind center.
        /// </summary>
        private Direction behindDirection;

        /// <summary>
        /// Gets the point forward of center.
        /// </summary>
        /// <value>
        /// The point forward of center.
        /// </value>
        public Point Forward {
            get {
                return this.forward;
            }
        }

        /// <summary>
        /// Gets the point behind the center.
        /// </summary>
        /// <value>
        /// The point behind the center.
        /// </value>
        public Point Behind {
            get {
                return this.behind;
            }
        }

        /// <summary>
        /// Gets the point to the left of center.
        /// </summary>
        /// <value>
        /// The point to the left of center.
        /// </value>
        public Point Left {
            get {
                return this.left;
            }
        }

        /// <summary>
        /// Gets the point to the right of center.
        /// </summary>
        /// <value>
        /// The point to the right of center.
        /// </value>
        public Point Right {
            get {
                return this.right;
            }
        }

        /// <summary>
        /// Gets the point forward and to the right of center.
        /// </summary>
        /// <value>
        /// The point forward and to the right of center.
        /// </value>
        public Point ForwardRight {
            get {
                return this.forwardRight;
            }
        }

        /// <summary>
        /// Gets the point forward and to the left of center.
        /// </summary>
        /// <value>
        /// The point forward and to the left of center.
        /// </value>
        public Point ForwardLeft {
            get {
                return this.forwardLeft;
            }
        }

        /// <summary>
        /// Gets the point behind and to the right of center.
        /// </summary>
        /// <value>
        /// The point behind and to the right of center.
        /// </value>
        public Point BehindRight {
            get {
                return this.behindRight;
            }
        }

        /// <summary>
        /// Gets the point behind and to the left of center.
        /// </summary>
        /// <value>
        /// The point behind and to the left of center.
        /// </value>
        public Point BehindLeft {
            get {
                return this.behindLeft;
            }
        }

        /// <summary>
        /// Gets the center point.
        /// </summary>
        /// <value>
        /// The center point.
        /// </value>
        public Point Center {
            get {
                return this.center;
            }
        }

        /// <summary>
        /// Gets the direction forward of center.
        /// </summary>
        /// <value>
        /// The direction forward of center.
        /// </value>
        public Direction ForwardDirection {
            get {
                return this.forwardDirection;
            }
        }

        /// <summary>
        /// Gets the direction to the left of center.
        /// </summary>
        /// <value>
        /// The direction to the left of center.
        /// </value>
        public Direction LeftDirection {
            get {
                return this.leftDirection;
            }
        }

        /// <summary>
        /// Gets the direction to the right of center.
        /// </summary>
        /// <value>
        /// The direction to the left of center.
        /// </value>
        public Direction RightDirection {
            get {
                return this.rightDirection;
            }
        }

        /// <summary>
        /// Gets the direction behind the center.
        /// </summary>
        /// <value>
        /// The direction behind the center.
        /// </value>
        public Direction BehindDirection {
            get {
                return this.behindDirection;
            }
        }

        /// <summary>
        /// A static method that returns a grid of points that are relative to a given location
        /// and direction that it is facing.
        /// </summary>
        /// <param name="location">Reference location.</param>
        /// <param name="direction">Direction that location is facing.</param>
        /// <returns>A DirectionalData object with all the points surrounding the given
        /// location. It also returns the 4 cardinal directions.</returns>
        public static DirectionalData DirectionalRelation(Point location, Direction direction) {
            DirectionalData result = new DirectionalData();
            DirectionalData offset = new DirectionalData();
            offset.forward.X = 0;
            offset.forward.Y = -1;
            offset.behind.X = 0;
            offset.behind.Y = 1;
            offset.left.X = -1;
            offset.left.Y = 0;
            offset.right.X = 1;
            offset.right.Y = 0;

            offset.forwardLeft.X = offset.left.X;
            offset.forwardLeft.Y = offset.forward.Y;
            offset.forwardRight.X = offset.right.X;
            offset.forwardRight.Y = offset.forward.Y;

            offset.behindLeft.X = offset.left.X;
            offset.behindLeft.Y = offset.behind.Y;
            offset.behindRight.X = offset.right.X;
            offset.behindRight.Y = offset.behind.Y;

            switch (direction) {
                case Direction.North:
                    result = offset;
                    result.forwardDirection = Direction.North;
                    result.leftDirection = Direction.West;
                    result.rightDirection = Direction.East;
                    result.behindDirection = Direction.South;
                    break;
                case Direction.South:
                    result.forward = offset.behind;
                    result.behind = offset.forward;
                    result.left = offset.right;
                    result.right = offset.left;
                    result.forwardLeft = offset.behindRight;
                    result.forwardRight = offset.behindLeft;
                    result.behindLeft = offset.forwardRight;
                    result.behindRight = offset.forwardLeft;
                    result.forwardDirection = Direction.South;
                    result.leftDirection = Direction.East;
                    result.rightDirection = Direction.West;
                    result.behindDirection = Direction.North;
                    break;
                case Direction.East:
                    result.forward = offset.right;
                    result.behind = offset.left;
                    result.left = offset.forward;
                    result.right = offset.behind;
                    result.forwardLeft = offset.forwardRight;
                    result.forwardRight = offset.behindRight;
                    result.behindLeft = offset.forwardLeft;
                    result.behindRight = offset.behindLeft;
                    result.forwardDirection = Direction.East;
                    result.leftDirection = Direction.North;
                    result.rightDirection = Direction.South;
                    result.behindDirection = Direction.West;
                    break;
                case Direction.West:
                    result.forward = offset.left;
                    result.behind = offset.right;
                    result.left = offset.behind;
                    result.right = offset.forward;
                    result.forwardLeft = offset.behindLeft;
                    result.forwardRight = offset.forwardLeft;
                    result.behindLeft = offset.behindRight;
                    result.behindRight = offset.behindRight;
                    result.forwardDirection = Direction.West;
                    result.leftDirection = Direction.South;
                    result.rightDirection = Direction.North;
                    result.behindDirection = Direction.East;
                    break;
            }
            
            result.forward.Offset(location);
            result.behind.Offset(location);
            result.left.Offset(location);
            result.right.Offset(location);
            result.forwardLeft.Offset(location);
            result.forwardRight.Offset(location);
            result.behindLeft.Offset(location);
            result.behindRight.Offset(location);
            result.center = location;

            return result;
        }
        
        /// <summary>
        /// Method to convert the points within the structure to an array of Points.
        /// The points are listed from Forward Left to Behind Right, going from Left
        /// to Right then Forward to Behind.
        /// </summary>
        /// <returns>A Point array of locations.</returns>
        public Point[] ToArray() {
            Point[] temp = new Point[9];
            temp[0] = this.forwardLeft;
            temp[1] = this.forward;
            temp[2] = this.forwardRight;
            temp[3] = this.left;
            temp[4] = this.center;
            temp[5] = this.right;
            temp[6] = this.behindLeft;
            temp[7] = this.behind;
            temp[8] = this.behindRight;
            return temp;
        }
    }
}
